package com.sharp.wechat.service.auth;

import com.sharp.authorization.service.token.TokenService;
import com.sharp.authorization.vo.login.LoginRes;
import com.sharp.kernel.constant.err.ErrCodeSys;
import com.sharp.kernel.exception.ServiceException;
import com.sharp.framework.service.cache.FrameCacheService;
import com.sharp.framework.service.rest.RestService;
import com.sharp.kernel.validate.Validator;
import com.sharp.wechat.constant.WechatConst;
import com.sharp.wechat.constant.WechatTokenItem;
import com.sharp.wechat.constant.WechatUrlConst;
import com.sharp.wechat.constant.err.WechatErrCode;
import com.sharp.wechat.po.WechatBaseRes;
import com.sharp.wechat.po.auth.AuthTokenRes;
import com.sharp.wechat.po.auth.AuthUserInfoReq;
import com.sharp.wechat.po.auth.AuthUserInfoRes;
import com.sharp.wechat.service.account.SyncAccountService;
import com.sharp.wechat.vo.auth.AuthReq;
import com.sharp.wechat.vo.auth.AuthRes;
import com.sharp.wechat.vo.auth.AuthUrlReq;
import com.sharp.wechat.vo.auth.AuthUrlRes;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.util.Map;

/**
 * Title: WechatAuthService
 * Description: Copyright: Copyright (c) 2019 Company: BHFAE
 *
 * @author Sharp
 * @date 2020/6/19 10:51
 */
@Service
public class WechatAuthService {

    @Resource
    private RestService restService;
    @Resource
    private TokenService tokenService;
    @Resource
    private FrameCacheService frameCacheService;
    @Resource
    private SyncAccountService syncAccountService;

    public AuthUrlRes getOAuthUrl(AuthUrlReq req) {
        String url = buildOAuth2Url(req);
        AuthUrlRes res = new AuthUrlRes();
        res.setUrl(url);
        return res;
    }

    public String buildOAuth2Url(AuthUrlReq req) {
        try {
            String wxCorpId = frameCacheService.getParamValueAvail(WechatConst.WECHAT_PUBLIC_APP_ID);
            String encodeRedirectUrl = URLEncoder.encode(req.getRedirectUrl(), "UTF-8");
            return String.format(WechatUrlConst.WECHAT_PUBLIC_OAUTH_URL_FORMAT, wxCorpId, encodeRedirectUrl, req.getState());
        } catch (Exception e) {
            Validator.assertException(e);
            return null;
        }
    }

    public AuthRes login(AuthReq req) {
        String publicAppId = frameCacheService.getParamValueAvail(WechatConst.WECHAT_PUBLIC_APP_ID);
        String publicSecret = frameCacheService.getParamValueAvail(WechatConst.WECHAT_PUBLIC_APP_SECRET);
        String getAccessTokenUrl = String.format(WechatUrlConst.WECHAT_PUBLIC_OAUTH_ACCESS_TOKEN_GET_URL_FORMAT,
                publicAppId, publicSecret, req.getCode());
        AuthTokenRes authTokenRes = restService.get(getAccessTokenUrl, AuthTokenRes.class);
        Validator.assertNotBlank(authTokenRes.getOpenId(), ErrCodeSys.SYS_SESSION_TIME_OUT);
        AuthUserInfoReq authUserInfoReq = buildAuthUserInfoReq(authTokenRes);
        AuthUserInfoRes res = restService.get(WechatUrlConst.WECHAT_PUBLIC_OAUTH_USER_INFO_GET_URL, authUserInfoReq,
                AuthUserInfoRes.class);
        validateWechatBaseRes(res);
        LoginRes loginRes = syncAccountService.loginOrReg(res.getOpenId(), res.getUnionId(), res.getNickName(),
                res.getHeadImgUrl());
        fillToken(loginRes.getAccessToken(), res);
        return buildAuthRes(loginRes, res);
    }

    private AuthUserInfoReq buildAuthUserInfoReq(AuthTokenRes authTokenRes) {
        AuthUserInfoReq authUserInfoReq = new AuthUserInfoReq();
        authUserInfoReq.setOpenId(authTokenRes.getOpenId());
        authUserInfoReq.setAccessToken(authTokenRes.getAccessToken());
        return authUserInfoReq;
    }

    private void validateWechatBaseRes(WechatBaseRes res) {
        if (res.getErrCode() != null) {
            throw new ServiceException(WechatErrCode.WECHAT_SERVER_ERROR, res.getErrCode(), res.getErrMsg());
        }
    }

    private void fillToken(String token, AuthUserInfoRes authUserInfoRes) {
        Map<String, Object> map = tokenService.getTokenValue(token);
        map.put(WechatTokenItem.OPEN_ID.name(), authUserInfoRes.getOpenId());
        map.put(WechatTokenItem.NICK_NAME.name(), authUserInfoRes.getNickName());
        map.put(WechatTokenItem.AVATAR.name(), authUserInfoRes.getHeadImgUrl());
        map.put(WechatTokenItem.SEX.name(), authUserInfoRes.getSex());
        map.put(WechatTokenItem.PROVINCE.name(), authUserInfoRes.getProvince());
        map.put(WechatTokenItem.CITY.name(), authUserInfoRes.getCity());
        map.put(WechatTokenItem.COUNTRY.name(), authUserInfoRes.getCountry());
        map.put(WechatTokenItem.PRIVILEGE.name(), authUserInfoRes.getPrivilege());
        map.put(WechatTokenItem.UNION_ID.name(), authUserInfoRes.getUnionId());
        tokenService.setTokenValue(token, map);
    }

    private AuthRes buildAuthRes(LoginRes loginRes, AuthUserInfoRes authUserInfoRes) {
        AuthRes res = new AuthRes();
        res.setToken(loginRes.getAccessToken());
        res.setUserId(loginRes.getCustomerNumber());
        res.setHeadImgUrl(authUserInfoRes.getHeadImgUrl());
        res.setNickName(authUserInfoRes.getNickName());
        return res;
    }

    public AuthRes bindPhoneNumber(String phoneNumber) {
        return syncAccountService.loginOrRegByPhoneNumber(phoneNumber);
    }

}
